package ch.ethz.fcl.metrobuzz.render.interchange.mrt;

import java.util.ArrayList;
import java.util.List;

import org.lwjgl.opengl.GL11;

import ch.ethz.fcl.metrobuzz.MBContainer;
import ch.ethz.fcl.metrobuzz.MBProperty;
import ch.ethz.fcl.metrobuzz.data.interchange.Junction;
import ch.ethz.fcl.metrobuzz.data.scene.basemap.Edge;
import ch.ethz.fcl.metrobuzz.data.scene.basemap.Edge.EdgeType;
import ch.ethz.fcl.metrobuzz.data.singapore.SGInterchange;
import ch.ethz.fcl.metrobuzz.render.techniques.colors.MBColorTable;
import ch.ethz.fcl.metrobuzz.render.techniques.colors.SGMRTColorTable;
import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Rectangle;
import ch.ethz.fcl.metrobuzz.tools.MBGL;
import ch.ethz.fcl.metrofont.Pen;

public class MRTInterchangeRender {
	private MBContainer container = null;
	private SGInterchange sr = null;

	private ArrayList<Edge> mrtEdges;

	private ArrayList<Edge> roadEdges;

	public MRTInterchangeRender(MBContainer container, SGInterchange sr) {
		this.container = container;

		this.sr = sr;

		initMRTEdges(container.getData().getRoadNetwork().getPassingEdges());
	}

	public void render(Rectangle bound) {
		MBGL.enableBlend();

		rendEdges();

		float distance = container.getViewer().getCamera().getDistance();

		if (MBProperty.OD) {
			if (distance < 1.0f)
				renderMark(bound);
		} else if (MBProperty.MRT) {
			// if (distance < 0.4f)
			// displayMRTName(bound);

			// else
			if (distance < 1.0f)
				renderMark(bound);
		}

		GL11.glDisable(GL11.GL_BLEND);
	}

	protected void renderMark(Rectangle bound) {
		ArrayList<Junction> jns = sr.getJunctions();

		float square_size = container.getViewer().getProjection()
				.getWorldDistance(4);

		float alpha = 0.7f;
		for (int i = 0; i < jns.size(); i++) {
			Junction jn = jns.get(i);
			if (renderMRT(jn)) {
				if (bound.contains(jn.getCircosCentroid())) {
					float width = 0;
					if (jn.isMRTNode("EW") || jn.isMRTNode("CG")) {
						width += square_size;
					}
					if (jn.isMRTNode("NS")) {
						width += square_size;
					}
					if (jn.isMRTNode("NE")) {
						width += square_size;
					}
					if (jn.isMRTNode("CC")) {
						width += square_size;
					}
					float x = jn.getCircosCentroid().getX() - width / 2;
					float y = jn.getCircosCentroid().getY() - square_size / 2;
					if (jn.isMRTNode("EW") || jn.isMRTNode("CG")) {
						SGMRTColorTable.assignSubwayColor(EdgeType.EW, alpha);
						renderSquare(x, y, square_size, square_size);
						x += square_size;
					}
					if (jn.isMRTNode("NS")) {
						SGMRTColorTable.assignSubwayColor(EdgeType.NS, alpha);
						renderSquare(x, y, square_size, square_size);
						x += square_size;
					}
					if (jn.isMRTNode("NE")) {
						SGMRTColorTable.assignSubwayColor(EdgeType.NE, alpha);
						renderSquare(x, y, square_size, square_size);
						x += square_size;
					}
					if (jn.isMRTNode("CC")) {
						SGMRTColorTable.assignSubwayColor(EdgeType.CC, alpha);
						renderSquare(x, y, square_size, square_size);
						x += square_size;
					}
				}
			}
		}
	}

	private void renderSquare(float x, float y, float width, float height) {
		// enable wire-frame
		GL11.glPolygonMode(GL11.GL_FRONT, GL11.GL_LINE);
		GL11.glBegin(GL11.GL_QUADS);
		GL11.glVertex3f(x, y, 0);
		GL11.glVertex3f(x + width, y, 0);
		GL11.glVertex3f(x + width, y + height, 0);
		GL11.glVertex3f(x, y + height, 0);
		GL11.glEnd();

		// restore regular rendering
		GL11.glPolygonMode(GL11.GL_FRONT, GL11.GL_FILL);
	}

	protected void displayMRTName(Rectangle bound) {
		ArrayList<Junction> jns = sr.getJunctions();

		float wordSize = container.getViewer().getProjection()
				.getWorldDistance(20);
		float height = wordSize * 1.5f;
		float width = wordSize * 3.0f;

		for (int i = 0; i < jns.size(); i++) {
			Junction jn = jns.get(i);
			if (renderMRT(jn) && bound.contains(jn.getCircosCentroid())) {
				String id = jn.getNodes().get(0).getId();
				Pen pen = new Pen(0, 0, wordSize);

				float startX = jn.getCircosCentroid().getX() - id.length() / 4
						* wordSize;
				float startY = jn.getCircosCentroid().getY();
				float x = startX;
				float y = startY;
				String[] stations = id.split("/");
				if (jn.isMRTNode("EW")) {
					SGMRTColorTable.assignSubwayColor(EdgeType.EW, 1.0f);
					renderSquare(x, y, width, height);
					for (int j = 0; j < stations.length; j++)
						if (stations[j].startsWith("EW")) {
							float textlength = stations[j].length() * wordSize;
							pen.setX(x + width / 2 - textlength / 3);
							pen.setY(y + height / 2 - wordSize / 2);
							MBColorTable.assignColor(MBColorTable.WHITE, 1.0f);
							container.getFont().display(stations[j], pen);
						}
					x += width;
				}
				if (jn.isMRTNode("CG") && stations.length == 1) {
					SGMRTColorTable.assignSubwayColor(EdgeType.EW, 1.0f);
					renderSquare(x, y, width, height);
					for (int j = 0; j < stations.length; j++)
						if (stations[j].startsWith("CG")) {
							float textlength = stations[j].length() * wordSize;
							pen.setX(x + width / 2 - textlength / 3);
							pen.setY(y + height / 2 - wordSize / 2);
							MBColorTable.assignColor(MBColorTable.WHITE, 1.0f);
							container.getFont().display(stations[j], pen);
						}
					x += width;
				}
				if (jn.isMRTNode("NS")) {
					SGMRTColorTable.assignSubwayColor(EdgeType.NS, 1.0f);
					renderSquare(x, y, width, height);
					for (int j = 0; j < stations.length; j++)
						if (stations[j].startsWith("NS")) {
							float textlength = stations[j].length() * wordSize;
							pen.setX(x + width / 2 - textlength / 3);
							pen.setY(y + height / 2 - wordSize / 2);
							MBColorTable.assignColor(MBColorTable.WHITE, 1.0f);
							container.getFont().display(stations[j], pen);
						}
					x += width;
				}
				if (jn.isMRTNode("NE")) {
					SGMRTColorTable.assignSubwayColor(EdgeType.NE, 1.0f);
					renderSquare(x, y, width, height);
					for (int j = 0; j < stations.length; j++)
						if (stations[j].startsWith("NE")) {
							float textlength = stations[j].length() * wordSize;
							pen.setX(x + width / 2 - textlength / 3);
							pen.setY(y + height / 2 - wordSize / 2);
							MBColorTable.assignColor(MBColorTable.WHITE, 1.0f);
							container.getFont().display(stations[j], pen);
						}
					x += width;
				}
				if (jn.isMRTNode("CC")) {
					SGMRTColorTable.assignSubwayColor(EdgeType.CC, 1.0f);
					renderSquare(x, y, width, height);
					for (int j = 0; j < stations.length; j++)
						if (stations[j].startsWith("CC")) {
							float textlength = stations[j].length() * wordSize;
							pen.setX(x + width / 2 - textlength / 3);
							pen.setY(y + height / 2 - wordSize / 2);
							MBColorTable.assignColor(MBColorTable.WHITE, 1.0f);
							container.getFont().display(stations[j], pen);
						}
					x += width;
				}

				String name = container.getData().getSGInfo().getMRTStations()
						.getName(id);
				if (name == null)
					continue;
				float name_length = container.getFont().getLength(name,
						pen.getFontSize());
				pen.setX((startX + x) / 2 - name_length / 2);
				pen.setY(y - wordSize);
				MBColorTable.assignColor(MBColorTable.BLACK, 1.0f);
				container.getFont().display(name, pen);
			}
		}
	}

	protected void renderJunctionInterchange(Rectangle rec) {
		ArrayList<Junction> jns = sr.getJunctions();

		for (int i = 0; i < jns.size(); i++) {
			Junction jn = jns.get(i);
			if (renderMRT(jn))
				jn.render(rec, container.getFont());
		}
	}

	private void rendEdges() {
		GL11.glLineWidth(2.0f);

		float alpha = 0.2f;
		GL11.glBegin(GL11.GL_LINES);
		for (Edge edge : mrtEdges) {
			if ((edge.getType() & EdgeType.EW) != 0) {
				SGMRTColorTable.assignSubwayColor(EdgeType.EW, alpha);
			} else if ((edge.getType() & EdgeType.NS) != 0) {
				SGMRTColorTable.assignSubwayColor(EdgeType.NS, alpha);
			} else if ((edge.getType() & EdgeType.CC) != 0) {
				SGMRTColorTable.assignSubwayColor(EdgeType.CC, alpha);
			} else if ((edge.getType() & EdgeType.NE) != 0) {
				SGMRTColorTable.assignSubwayColor(EdgeType.NE, alpha);
			}

			edge.render();
		}
		GL11.glEnd();
	}

	private void initMRTEdges(List<Edge> edges) {
		mrtEdges = new ArrayList<Edge>();
		roadEdges = new ArrayList<Edge>();

		for (Edge e : edges)
			if (((e.getType() & EdgeType.EW) != 0)
					|| ((e.getType() & EdgeType.NS) != 0)
					|| ((e.getType() & EdgeType.NE) != 0)
					|| ((e.getType() & EdgeType.CC) != 0)) {
				mrtEdges.add(e);
			} else
				roadEdges.add(e);

	}

	public static boolean renderMRT(Junction jn) {
		if (jn.isMRTNode("EW") || jn.isMRTNode("CG"))
			return true;
		if (jn.isMRTNode("NS"))
			return true;
		if (jn.isMRTNode("NE"))
			return true;
		if (jn.isMRTNode("CC"))
			return true;
		return false;
	}
}
